#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>
#include <sys/stat.h>

#include "avi.h"
#include "sdmng.h"
#include "record.h"
#include "exception.h"
#include "debug.h"

static int rsc_device_handle(const char *dname,int status,void *priv)
{
    if(dname == NULL)
    {
	SLOG(ERR,"device mount name is NULL.\n");
	return -1;
    }
    int ret = 0;
    int devid = rsc_get_sd_devid(dname);
    struct sd_info info;
    if(devid < 0)
    {
	SLOG(ERR,"device mount [%s] is invalid!\n",dname);
	return -1;
    }
    memset(&info,0,sizeof(info));
    switch(status&MASK_DEV_STA)
    {
	case DEV_STA_WRITE_ERR:/// fix device
	    rsc_set_dev_busy(devid,RSC_FCHECK_FLAG);
	    break;

	case DEV_STA_INVAL:
	    SLOG(WRN,"device[%s] doesnot exist or is bad!\n",dname);
	    break;

	default:
	    break;
    }

    return ret;
}

static int rsc_content_handle(const char *fname,int status,void *priv)
{
    if(fname == NULL)
    {
	SLOG(ERR,"file name is NULl.\n");
	return -1;
    }
    int ret = 0;

    switch(status&MASK_CONT_STA)
    {/// do nothing
	case CONT_STA_INIT:
	    break;
	case CONT_STA_WING:
	    break;
	case CONT_STA_WEND:
	    break;
    }

    return ret;
}

static struct exception_handle rsc_ehdl = 
{
    .dev_ehdl= rsc_device_handle,
    .cont_ehdl= rsc_content_handle,
};

#define RSC_REC_MAX_CHN 7
static struct exception_meta rsc_exmate[RSC_REC_MAX_CHN];

static int init_exception_meta(void)
{
    int i = 0;
    for(i=0;i<RSC_REC_MAX_CHN;i++)
    {
	rsc_exmate[i].chn_id = i;
	rsc_exmate[i].status = 0;
	memset(rsc_exmate[i].dev_mpoint,0,sizeof(rsc_exmate[i].dev_mpoint));
	memset(rsc_exmate[i].prev_mpoint,0,sizeof(rsc_exmate[i].prev_mpoint));
	memset(rsc_exmate[i].fname,0,sizeof(rsc_exmate[i].fname));
    }
    return 0;
}

int rsc_exception_init(struct exception_handle *ehdl, int devnum, char *mpoint)
{
    if(ehdl != NULL)
    {
	rsc_ehdl.dev_ehdl= ehdl->dev_ehdl;
	rsc_ehdl.cont_ehdl= ehdl->cont_ehdl;
    }
    if(devnum <= 0)
    {
	SLOG(ERR,"device num is invalid:%d\n",devnum);
	return -1;
    }
    int i = 0,j = 0,ret = 0, devid = 0;
    struct exception_meta emeta;
    char meta_dir[64]={0},meta_file[128]={0}, root[32] = {0};
    FILE *fp = NULL;

    init_exception_meta();

    /// scan device to find exceptin meta info
    for(i=0;i<devnum;i++)
    {
	if(rsc_get_sd_mpoint(i,root,sizeof(root))==0)
	    snprintf(meta_dir,sizeof(meta_dir),"%s/%s",root,".meta");
	else
	    continue;
	if(access(meta_dir,F_OK))
	    continue;
	for(j=0;j<RSC_REC_MAX_CHN;j++)
	{
	    memset(&emeta,0,sizeof(emeta));
	    snprintf(meta_file,sizeof(meta_file),"%s/chn_%d.me",meta_dir,j);
	    if(access(meta_file,R_OK))
		continue;
	    else
		devid = i;/// the last used device id
	    fp = fopen(meta_file,"rb");
	    if(fp==NULL)
		SLOG(ERR,"fopen %s err:%s\n",meta_file,strerror(errno));
	    else if((ret = fread(&emeta,sizeof(struct exception_meta),1,fp))!=1)
	    {
		SLOG(ERR,"fread %s fail,ret = %d\n",meta_file,ret);
		ret = -1;
		fclose(fp);
	    }
	    else // fix up
	    {
		char filename[128]={0}, *p = NULL,*q = NULL;
		int tlen = strlen(emeta.fname),flen = 0,dlen = 0, pos = 0;
		snprintf(filename,sizeof(filename),"%s",emeta.fname);
		if((p = strrchr(filename,'/'))!=NULL)
		{
		    flen = strlen(p);
		    *p = 0;
		    if((q=strrchr(filename,'/'))!=NULL)
			dlen = strlen(q);
		    pos = tlen - dlen - flen;
		}
		snprintf(filename,sizeof(filename),"%s%s",root,emeta.fname+pos);
		if(emeta.status&CONT_STA_INIT) 
		    remove(filename);
		else if(emeta.status&CONT_STA_WING)
		{
		    ret = avi_fix_handle(filename);
		    //ret = mav_fix_handle(filename);
		    SLOG(PRI,"mav_fix_handle [%s],ret = %d\n",filename,ret);
		}
		strcpy(mpoint,emeta.dev_mpoint);
		fclose(fp);
	    }
	    remove(meta_file);
	}
	remove(meta_dir);
    }

    return devid;
}

static int delete_prev_meta(const char *mpoint,int chn)
{
    char meta_dir[64],meta_file[128];

    snprintf(meta_dir,sizeof(meta_dir),"%s/%s",mpoint,".meta");
    snprintf(meta_file,sizeof(meta_file),"%s/chn_%d.me",meta_dir,chn);
    remove(meta_file);
    remove(meta_dir);

    return 0;
}

/**
 * fname absolute path and name
 */
int rsc_exception_handle(int chn,int status,const char *mpoint,const char *fname)
{
    if(chn < 0 || chn >= RSC_REC_MAX_CHN)
    {
	SLOG(ERR,"chn [%d] is invalid!\n",chn);
	return -1;
    }
    if(mpoint==NULL || fname==NULL)
    {
	SLOG(ERR,"null params!\n");
	return -1;
    }
    int ret = 0;
    FILE *fp = NULL;
    char meta_dir[64]={0},meta_file[128]={0};
    struct exception_meta *meta = &rsc_exmate[chn];

    if(strlen(meta->prev_mpoint)==0)
	strcpy(meta->prev_mpoint,mpoint);
    else if(strcmp(meta->prev_mpoint,mpoint))
    {/// delete obsolete .meta files
	delete_prev_meta(meta->prev_mpoint,chn);
	strcpy(meta->prev_mpoint,mpoint);
    }
    snprintf(meta_dir,sizeof(meta_dir),"%s/%s",mpoint,".meta");
    snprintf(meta_file,sizeof(meta_file),"%s/chn_%d.me",meta_dir,chn);
    mkdir(meta_dir,0777);

    meta->status = status;
    strcpy(meta->dev_mpoint,mpoint);
    strcpy(meta->fname,fname);

    /// exception handle
    if(status&MASK_DEV_STA)
	rsc_device_handle(meta->dev_mpoint,status,NULL);
    if(status&MASK_CONT_STA)
	rsc_content_handle(meta->fname,status,NULL);

    /// save info to flash
    fp = fopen(meta_file,"wb+");
    if(fp==NULL)
    {
	SLOG(ERR,"fopen %s err:%s\n",meta_file,strerror(errno));
	return -1;
    }
    ret = fwrite(meta,sizeof(struct exception_meta),1,fp);
    if(ret != 1)
    {
	SLOG(ERR,"status[%d]fwrite %s err:%s\n",status,meta_file,strerror(errno));
	fclose(fp);
	return -1;
    }
    fclose(fp);

    return 0;
}

